const DAY_NUM = 42
const WEEK_DAY_NUM = 7
const DATE_CHECK = /^(\d{4})-(\d{2})-(\d{2})$/
const weekMap = {
  0: '周日',
  1: '周一',
  2: '周二',
  3: '周三',
  4: '周四',
  5: '周五',
  6: '周六'
}
Component({
  options:{
    addGlobalClass: true
  },
  properties: {
    selectedDate: {
      type: String,
      value: ''
    },
    openDays: null,
    mode: {
      type: String,
      value: ''
    },
    showToday: {
      type: Boolean,
      value: true
    }
  },
  data: {
    pickDate: '',
    pickDateDisplay: '',
    tMonthFirstDayWeek: 0,
    allDays: [],
    selectedDate: '',
    today: '',
    dateRange: []
  },
  lifetimes: {
    ready() {
      this.initCalendar()
    }
  },
  methods: {
    initCalendar() {
      const now = new Date()
      if (!DATE_CHECK.test(this.data.selectedDate)) {
        this.setData({
          selectedDate: ''
        })
      }
      this.setData({
        today: this.parseTime(now, '{y}-{m}-{d}')
      })
      this.setCalendar(this.parseTime(now, '{y}-{m}'))
    },
    setCalendar(dateStr) {
      const self = this
      const selectDate = new Date(dateStr)
      const pickDate = self.parseTime(selectDate, '{y}-{m}')
      const dateSplit = dateStr.split('-')
      const thisYear = dateSplit[0]
      const thisMonth = dateSplit[1]
      const tempWeek = new Date(`${self.parseTime(selectDate, '{y}-{m}-')}01`).getDay()
      const tMonthFirstDayWeek = tempWeek === 0 ? WEEK_DAY_NUM : tempWeek

      const lastMonthOrigin = [...Array(self.getMonthDayNum(selectDate.getFullYear(), selectDate.getMonth())).keys()]
      const thisMonthOrigin = [...Array(self.getMonthDayNum(selectDate.getFullYear(), selectDate.getMonth() + 1)).keys()]
      const nextMonthOrigin = [...Array(self.getMonthDayNum(selectDate.getFullYear(), selectDate.getMonth() + 2)).keys()]
      // const lastMonthFinal = [...lastMonthOrigin].splice(lastMonthOrigin.length - (tMonthFirstDayWeek - 1), lastMonthOrigin.length)
      const lastMonthFinal = [...lastMonthOrigin].splice(lastMonthOrigin.length - tempWeek, lastMonthOrigin.length)
      const nextMonthFinal = [...nextMonthOrigin].splice(0, DAY_NUM - lastMonthFinal.length - thisMonthOrigin.length)

      const allDays = [
        ...this.mapMonth(lastMonthFinal, thisYear, Number(thisMonth) - 1, pickDate),
        ...this.mapMonth(thisMonthOrigin, thisYear, Number(thisMonth), pickDate),
        ...this.mapMonth(nextMonthFinal, thisYear, Number(thisMonth) + 1, pickDate)
      ]

      self.setData({
        pickDate,
        pickDateDisplay: self.parseTime(selectDate, '{y}年{m}月'),
        tMonthFirstDayWeek,
        allDays,
        originalAllDays: JSON.parse(JSON.stringify(allDays))
      })
    },

    mapMonth(dayArr, year, month, pickDate = null) {
      // 可选择日期
      const openDays = this.data.openDays
      const thisMonthNum = pickDate && Number(pickDate.split('-')[1])
      return dayArr.map(day => {
        const displayYear = month === 0 ? Number(year) - 1 : month === 13 ? Number(year) + 1 : year
        const dislpayMonth = month === 0 ? 12 : month === 13 ? 1 : month
        const date = `${displayYear}-${dislpayMonth < 10 ? `0${dislpayMonth}` : dislpayMonth}-${(day + 1) < 10 ? `0${day + 1}` : day + 1}`
        const week = weekMap[new Date(date).getDay()]
        const optional = openDays ? openDays.indexOf(date) > -1 : true

        return {
          optional,
          dateNumber: day + 1,
          date,
          week,
          position: thisMonthNum === month ? '' : month === thisMonthNum - 1 ? 'pre-month' : 'next-month'
        }
      })
    },

    bindPickDateChange(event) {
      const {
        value
      } = event.detail
      this.setData({
        pickDate: value,
        pickDateDisplay: this.parseTime(value, '{y}年{m}月')
      })
      this.setCalendar(value)
      this.triggerEvent('onPickDateChange', value)
    },
    // 获取某月天数
    getMonthDayNum(year, month) {
      const d = new Date(year, month, 0)
      return d.getDate()
    },
    control(event) {
      const {
        mode
      } = event.currentTarget.dataset
      const {
        pickDate
      } = this.data
      let dateArr = pickDate.split('-')
      let oldMonth = Number(dateArr[1])
      let oldYear = Number(dateArr[0])
      let newDate = ''
      switch (mode) {
        case 'pre':
          newDate = oldMonth === 1 ? `${oldYear - 1}-12` : `${oldYear}-${oldMonth - 1 < 10 ? `0${oldMonth - 1}` : oldMonth - 1}`
          break;
        case 'reset':
          newDate = this.data.selectedDate || new Date()
          if (this.data.mode === 'range') {
            this.setData({
              selectedDate: newDate,
              dateRange: []
            })
          } else {
            this.setData({
              selectedDate: this.parseTime(newDate, '{y}-{m}-{d}')
            })
          }
          break;
        case 'next':
          newDate = oldMonth === 12 ? `${oldYear + 1}-01` : `${oldYear}-${oldMonth + 1 < 10 ? `0${oldMonth + 1}` : oldMonth + 1}`
          break;
      }
      const timeParse = this.parseTime(new Date(newDate), '{y}-{m}')
      this.setCalendar(timeParse)
      if (mode !== 'reset' && this.data.mode === 'range') {
        this.findRange(this.data.dateRange)
      }
      this.triggerEvent('onControl', {
        mode,
        newDate: timeParse
      })
    },
    // 选择时间
    onPickDay(event) {
      const {
        day
      } = event.currentTarget.dataset
      // 不能选择
      if (!day.optional) return
      const { mode } = this.data
      if (mode === 'range') {
        this.onPickRangeDate(day)
      } else {
        this.setData({
          selectedDate: day.date
        })
        this.triggerEvent('onPickDay', day)
      }
    },
    /**
     * 选择区间时间
     * @param {string} day 当前点击的时间
     */
    onPickRangeDate(day) {
      const { length } = this.data.dateRange
      if (!length || length === 2) {
        // 没有开始时间或者有结束时间
        // 点击时间设置为开始时间，清空结束时间
        this.setStartRangeDay(day)
      } else {
        // 只有开始时间
        const startDayStamp = Date.parse(this.data.dateRange[0])
        const currentClickStamp = Date.parse(day.date)
        if (currentClickStamp <= startDayStamp) {
          // 点击时间小于开始时间，重置开始时间为点击时间
          this.setStartRangeDay(day)
        } else {
          // 点击时间大于开始时间，结束时间设置为点击时间
          this.setEndRangeDay(day)
        }
      }
    },
    /**
     * 设置区间开始时间
     * @param {string} day 点击时间
     */
    setStartRangeDay(day) {
      const { originalAllDays, dateRange } = this.data
      const allDays = JSON.parse(JSON.stringify(originalAllDays))
      const startIndex = allDays.findIndex(item => item.date === day.date)
      const newDay = { ...day }
      // 设置开始标志把结束标志置为false
      newDay.end = false
      newDay.start = true
      allDays.splice(startIndex, 1, { ...newDay })
      dateRange[0] = day.date
      dateRange.length = 1
      this.setData({ dateRange, allDays })
    },
    /**
     * 设置区间结束时间
     * @param {string} day 点击时间
     */
    setEndRangeDay(day) {
      const { dateRange } = this.data
      dateRange[1] = day.date
      this.setData({ dateRange })
      const rangeDays = this.findRange(dateRange)
      this.triggerEvent('onPickDay', rangeDays)
    },
    // 找出range内的日期(同时设置结束时间标志，再设置一遍开始标志，这样切换月份重绘页面时调用该方法来保持选中的区间)
    findRange(dateRange) {
      const minTimeStamp = Date.parse(dateRange[0])
      const maxTimeStamp = Date.parse(dateRange[1])
      let allDays = [...this.data.allDays]
      allDays.forEach(item => {
        const parseDate = Date.parse(item.date)
        item[`start`] = parseDate === minTimeStamp
        item[`inRange`] = parseDate < maxTimeStamp && parseDate > minTimeStamp
        item[`end`] = parseDate === maxTimeStamp
      })
      const inRangeDays = allDays.filter(item => item.inRange).map(item => item.date)
      this.setData({
        allDays
      })
      return [dateRange[0], ...inRangeDays, dateRange[1]]
    },
    parseTime(time, cFormat) {
      if (arguments.length === 0) {
        return null
      }
      const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
      let date
      if (typeof time === 'object') {
        date = time
      } else {
        if (('' + time).length === 10) time = parseInt(time) * 1000
        date = new Date(time)
      }
      const formatObj = {
        y: date.getFullYear(),
        m: date.getMonth() + 1,
        d: date.getDate(),
        h: date.getHours(),
        i: date.getMinutes(),
        s: date.getSeconds(),
        a: date.getDay()
      }
      const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
        let value = formatObj[key]
        if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
        if (result.length > 0 && value < 10) {
          value = '0' + value
        }
        return value || 0
      })
      return timeStr
    },
    handleRangeStyle(day, dateRange) {
      if (dateRange.indexOf(day.date) !== -1) return 'range-pick';
    }
  }
})